package com.mfz.common.scheduler;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.util.Date;
import java.util.List;

/**
 * 计划任务的实现对象。
 */
public class Scheduler implements Runnable {
	private static final Logger logger = LogManager.getLogger(Scheduler.class.getName());

	private List<Task> tasks;

	private Task runTask;
	private long pioneerRunTime;
	private boolean running = true;

	synchronized void changed(List<Task> tasks) {
		this.tasks = tasks;

		for (Task task : tasks) {
			pioneerRunTime = checkPositive(task.getNextRunTime(), "task.getNextRunTime()");
			runTask = task;
		}

		this.notify();
	}

	synchronized void stop() {
		logger.trace("开始关闭计划线程。");
		running = false;
		this.notify();
	}

	@Override
	public synchronized void run() {
		while (running) {
			try {
				while (tasks.size() == 0) {
					this.wait(60000);
				}

				getNextRunTaskTime();

				if (System.currentTimeMillis() < pioneerRunTime) {
					this.wait(pioneerRunTime - System.currentTimeMillis());
				}

				if (!running) {
					logger.trace("Scheduler线程结束。");
					return;
				}

				logger.trace("开始执行{}任务。", runTask.getClass().getSimpleName());
				runTask.run();
				logger.trace("任务{}执行结束。", runTask.getClass().getSimpleName());

			} catch (InterruptedException e) {
				logger.error("", e);
			} finally {
				pioneerRunTime = runTask.getNextRunTime();
			}
		}

		logger.trace("Scheduler线程结束。");
	}

	/**
	 * 得到最近的任务运行的时间
	 */
	private void getNextRunTaskTime() {
		for (Task task : tasks) {
			if (task.getNextRunTime() < pioneerRunTime) {
				runTask = task;
				pioneerRunTime = task.getNextRunTime();
			}
		}

		logger.info("下次执行时间为：" + new Date(pioneerRunTime));
	}

	public List<Task> getTasks() {
		return tasks;
	}

	/**
	 * Checks that the given argument is strictly positive. If it is, throws {@link IllegalArgumentException}.
	 * Otherwise, returns the argument.
	 */
	public static long checkPositive(long i, String name) {
		if (i <= 0) {
			throw new IllegalArgumentException(name + ": " + i + " (expected: > 0)");
		}
		return i;
	}
}
